package tinybase.ix;

import java.io.File;
import java.nio.ByteBuffer;
import tinybase.basic.RC;
import tinybase.basic.RedBase;
import tinybase.basic.RedBase.AttrType;
import tinybase.pf.PF_Manager;
import tinybase.basic.BytePointer;
import tinybase.pf.*;
import tinybase.ix.*;

public class IX_Manager {
	
	/*
	 *  private attributes
	 */
	
	private PF_Manager pfm;
	
	/*
	 *  public attributes and functions
	 */
	
	public PF_Manager getPFmagager(){
		return pfm;
	}
	
	public IX_Manager(PF_Manager pfm) {
		this.pfm=pfm;		
	}

    // Create a new Index
    public RC createIndex(String fileName, int indexNo,
                   AttrType attrType, int attrLength) {
    	   RC rc;
           String fileNameIndexNo;
           PF_FileHandle pfFileHandle=new PF_FileHandle();
           PF_PageHandle pageHandle=new PF_PageHandle();
           BytePointer pNode=new BytePointer();
    	 // Sanity Check: fileName
    	   if (fileName == null)
    	      // Test: Null fileName
    	      return (tinybase.basic.RC.IX_NULLPOINTER);

    	   // Sanity Check: indexNo should be non-negative
    	   // Note that PF_Manager::CreateFile() will take care of fileName
    	   if (indexNo < 0)
    	      // Test: invalid index number
    	      return (tinybase.basic.RC.IX_INVALIDINDEXNO);

    	   // Sanity Check: attrType, attrLength
    	   switch (attrType) {
    	   case INT:
    	   case FLOAT:
    	      if (attrLength != 4)
    	         // Test: wrong attrLength
    	         return (tinybase.basic.RC.IX_INVALIDATTR);
    	      break;

    	   case STRING:
    	      if (attrLength < 1 || attrLength >RedBase.MAXSTRINGLEN)
    	         // Test: wrong attrLength
    	         return (tinybase.basic.RC.IX_INVALIDATTR);
    	      break;

    	   default:
    	      // Test: wrong attrType
    	      return (tinybase.basic.RC.IX_INVALIDATTR);
    	   }
    	   // Allocate memory for "fileName.indexNo"
    	   if ((fileNameIndexNo =fileName+"."+indexNo)== null)
    	      return (tinybase.basic.RC.IX_NOMEM);

    	   fileNameIndexNo= fileName + "." + indexNo;
//    	   System.out.println(fileNameIndexNo);
//    	   System.out.printf(fileNameIndexNo, "%s.%u",  fileName, indexNo);

    	   // Call PF_Manager::CreateFile()
    	   File f= new File(fileNameIndexNo);
    	   if (f.exists())
    		   f.delete();
    	   
    	   if ((rc = pfm.createFile(fileNameIndexNo))!=RC.SUCCESS)
    	      // Test: existing fileName, wrong permission
    		   return rc;
    	   // Call PF_Manager::OpenFile()
    	   if ((rc = pfm.openFile(fileNameIndexNo, pfFileHandle))!=RC.SUCCESS)
    	      // Should not happen
    	      return rc;

    	   // Allocate the root page (pageNum must be 0)
    	   if ((rc = pfFileHandle.allocatePage(pageHandle))!=RC.SUCCESS)
    	      // Should not happen
    	     return rc;
    	  
    	   // Get a pointer where header information will be written
    	   if ((rc = pageHandle.getData(pNode))!=RC.SUCCESS)
    	      // Should not happen
    	    return rc;


    	   // Write the root node
    	    ByteBuffer buf=ByteBuffer.wrap(pNode.getArray());
    	    buf.putShort(PF_PageHandle.DATASTART_OFFSET, (short)IX_Internal.IX_LEAF_NODE);
    	    buf.putShort(PF_PageHandle.DATASTART_OFFSET+2,(short)0);
    	    buf.putInt(PF_PageHandle.DATASTART_OFFSET+2+2, attrType.getValue());
    	    buf.putInt(PF_PageHandle.DATASTART_OFFSET+2+2+4,attrLength);
    	       	    
    	   // Mark the header page as dirty
    	   if ((rc = pfFileHandle.markDirty(0))!=RC.SUCCESS)
    	      // Should not happen
    	      return rc;
    	   
    	   // Unpin the header page
    	   if ((rc = pfFileHandle.unpinPage(0))!=RC.SUCCESS)
    	      // Should not happen
    	      return rc;
    	   
    	   // Call PF_Manager::CloseFile()
    	   if ((rc = pfm.closeFile(pfFileHandle))!=RC.SUCCESS)
    	      // Should not happen
    	      return rc;

    	   // Return ok
    	return RC.SUCCESS;
    }

    // Destroy and Index
    public RC destroyIndex(String fileName, int indexNo) {
    	   RC rc;
    	   String fileNameIndexNo;

    	   // Sanity Check: fileName
    	   if (fileName == null)
    	      // Test: Null fileName
    	      return (tinybase.basic.RC.IX_NULLPOINTER);

    	   // Sanity Check: indexNo should be non-negative
    	   // Note that PF_Manager::CreateFile() will take care of fileName
    	   if (indexNo < 0)
    	      // Test: invalid index number
    	      return (tinybase.basic.RC.IX_INVALIDINDEXNO);

    	   // Allocate memory for "fileName.indexNo"
    	   if ((fileNameIndexNo =fileName+"."+indexNo)== null)
     	      return (tinybase.basic.RC.IX_NOMEM);

    	   fileNameIndexNo= fileName + "." + indexNo;
//    	   System.out.printf(fileNameIndexNo, "%s.%u", fileName, indexNo);

    	   // Call PF_Manager::DestroyFile()
    	   if ((rc = pfm.destroyFile(fileNameIndexNo))!=RC.SUCCESS)
    	      // Test: non-existing fileName, wrong permission
    	     return rc;    	  
    	   // Return ok
    	return RC.SUCCESS;
    }

    // Open an Index
    public RC openIndex(String fileName, int indexNo,
                 IndexHandle indexHandle) {
    	   RC rc;
    	   String fileNameIndexNo;
    	   PF_PageHandle pageHandle= new PF_PageHandle();
    	   BytePointer pNode=new BytePointer();

    	   // Sanity Check: fileName
    	   if (fileName == null)
    	      // Test: Null fileName
    	      return (tinybase.basic.RC.IX_NULLPOINTER);

    	   // Sanity Check: indexNo should be non-negative
    	   // Note that PF_Manager::CreateFile() will take care of fileName
    	   if (indexNo < 0)
    	      // Test: invalid index number
    	      return (tinybase.basic.RC.IX_INVALIDINDEXNO);

    	   // Allocate memory for "fileName.indexNo"
    	   if ((fileNameIndexNo =fileName+"."+indexNo)== null)
    	      return (tinybase.basic.RC.IX_NOMEM);

    	   fileNameIndexNo= fileName + "." + indexNo;
//    	  System.out.printf(fileNameIndexNo, "%s.%u", fileName, indexNo);

    	   // Call PF_Manager::OpenFile()
    	   if ((rc = pfm.openFile(fileNameIndexNo, indexHandle.getPfFileHandle()))!=RC.SUCCESS)
    	      // Test: non-existing fileName, opened indexHandle
    	      return rc;

    	   // Get the root node
    	   if((rc = indexHandle.getPfFileHandle().getFirstPage(pageHandle))!=RC.SUCCESS)
    	      // Test: invalid file
    	      return rc;

    	   // Get a data pointer
    	   if ((rc = pageHandle.getData(pNode))!=RC.SUCCESS)
    	      // Should not happen
    	      return rc;

    	   // Read the common header
    	   ByteBuffer buf=ByteBuffer.wrap(pNode.getArray());
    	   
    	   indexHandle.setAttrType(buf.getInt(pageHandle.DATASTART_OFFSET+2+2));
    	   indexHandle.setAttrLength(buf.getInt(pageHandle.DATASTART_OFFSET+2+2+4));

    	   // Unpin the header page
    	   if ((rc = indexHandle.getPfFileHandle().unpinPage(0))!=RC.SUCCESS)
    	      // Should not happen
    	      return rc;


    	   // Return ok
    	   return RC.SUCCESS;

    }

    // Close an Index
    public RC closeIndex(IndexHandle indexHandle) {
    	  RC rc;

    	   // Call PF_Manager::CloseFile()
    	   if ((rc = pfm.closeFile(indexHandle.getPfFileHandle()))!=RC.SUCCESS)
    	      // Test: unopened(closed) indexHandle
    	     return rc;

    	   // Reset member variables
    	   indexHandle.setAttrType (tinybase.basic.RedBase.AttrType.INT);
    	   indexHandle.setAttrLength(0);
    	   indexHandle.setDistinctValsInc(0);
    	   indexHandle.setDepthInc(0);
    	   
    	   
    	   // Return ok
    	return RC.SUCCESS;
    }


    // Copy constructor
    public  IX_Manager(IX_Manager manager) {
    	this.pfm=manager.getPFmagager();
    	
    }

}